/*
 * File Name:               XBTreeGenerator.cs
 * 
 * Description:             普通类
 * Author:                  lisiyu <576603306@qq.com>

 * Create Date:             2017/08/15
 */

using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
using UnityEditor;
using UnityEngine;
using XBehaviorTree;
using GameAI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Collections;

namespace GameAI
{

    public class XBTreeGenerator : EditorWindow
    {
        [MenuItem("Tools/Behavior Designer/生成构造代码")]
        static void onOpen()
        {
            var aiList = new List<ExternalBehavior>(4);

            aiList.Add(Resources.Load<ExternalBehavior>("AI_config/Common_Control"));
            aiList.Add(Resources.Load<ExternalBehavior>("AI_config/PlayerPosition"));
            aiList.Add(Resources.Load<ExternalBehavior>("AI_config/PlayerMoveType"));

            //var config = Resources.Load<FormationAIConfig>("AI_config/FormationConfig");
            //foreach (var formation in config.formationList)
            //{
            //    foreach (var pos in formation.positionList)
            //    {
            //        if (pos.AI == null || aiList.Contains(pos.AI))
            //            continue;

            //        aiList.Add(pos.AI);
            //    }
            //}

            string ret = @"/*
 * File Name:               AICreator.cs
 * Description:             自动生成的代码类 请不要手动修改
 */

using GameAI;
using XBehaviorTree;
using System.Collections.Generic;

public class AICreator
    {
#CONSTRUCTORS#

#FUNCTIONS#
    }
";
            strfuncs = "";

            foreach (var ai in aiList)
            {
                var obj = new GameObject("tempAi");
                var aiTree = obj.AddComponent<BehaviorTree>();
                aiTree.RestartWhenComplete = false;
                aiTree.StartWhenEnabled = false;
                aiTree.ExternalBehavior = ai;
                aiTree.CheckForSerialization();

                var manager = obj.AddComponent<BehaviorManager>();
                manager.EnableBehavior(aiTree);

                ret = parse(ret, aiTree);
                GameObject.DestroyImmediate(obj);
            }

            ret = ret.Replace("#CONSTRUCTORS#", "");
            ret = ret.Replace("#FUNCTIONS#", strfuncs);

            File.WriteAllText("Assets/Code/AIScript/AICreator.cs", ret);
        }

        private static string strfuncs;
        private static Stack<string> logPaths;

        private static string parse(string template, BehaviorTree ai)
        {
            logPaths = new Stack<string>();
            return template.Replace("#CONSTRUCTORS#", parse(ai.ExternalBehavior.name, ai.GetBehaviorSource().RootTask) + "\n#CONSTRUCTORS#");
        }

        private static string parse(string name, Task task)
        {
            var template = @"        public static XBehaviorTree.XBehaviorTree create#NAME#()
        {
            return new XBehaviorTree.XBehaviorTree(null)
            {
                mTask = #CONTENT#
            };
        }";

            logPaths.Push(name);
            return template.Replace("#NAME#", name).Replace("#CONTENT#", parse(task));
        }

        private static string parse(Task task, int index = 0)
        {
            logPaths.Push(task.GetType().Name + index);
            if (task is Sequence)
            {
                return parse(task as Sequence);
            }
            else if (task is Selector)
            {
                return parse(task as Selector);
            }
            else if (task is Inverter)
            {
                return parse(task as Inverter);
            }
            else if (task is UnknownTask)
            {
                var log = "";
                foreach (var item in logPaths)
                {
                    log += item + " <-- ";
                }
                Debug.LogError("发现未知节点 " + log);
                return "";
            }
            else
            {
                return parseClass(task);
            }
        }

        private static string parse(Sequence sequence)
        {
            var content = "";
            var index = 0;
            foreach (var child in sequence.Children)
            {
                if (child.Disabled)
                    continue;
                content += parse(child, index++);
                content += ",";
                logPaths.Pop();
            }

            var func = string.Format("new Sequence_BTree(null){{ \n mChilds = new ITask_BTree[] {{ {0} }} }}", content);
            var logPath = getLogPath();
            strfuncs += string.Format("\n private static ITask_BTree create{0}() {{ return {1};}}", logPath, func);

            return string.Format("create{0}()", logPath);
        }

        private static string parse(Selector selector)
        {
            var content = "";
            var index = 0;
            foreach (var child in selector.Children)
            {
                if (child.Disabled)
                    continue;

                content += parse(child, index++);
                content += ",";
                logPaths.Pop();
            }


            var func = string.Format("new Selector_BTree(null){{ \n mChilds = new ITask_BTree[] {{ {0} }} }}", content);
            var logPath = getLogPath();
            strfuncs += string.Format("\n private static ITask_BTree create{0}() {{ return {1};}}", logPath, func);

            return string.Format("create{0}()", logPath);
        }

        private static string parse(Inverter inverter)
        {
            var content = parse(inverter.Children[0]);
            logPaths.Pop();
            return string.Format("new Inverter_BTree(null){{ \n mChild = {0} }}", content);
        }

        private static string parseClass(object obj)
        {
            var content = "";
            var fields = obj.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.SetField | System.Reflection.BindingFlags.Instance);
            foreach (var field in fields)
            {
                content += field.Name;
                content += " = ";

                var value = field.GetValue(obj);
                content += parseValue(value);

                content += ", ";
            }

            return string.Format("new {0}(){{ {1} }}", obj.GetType().FullName.Replace('+', '.'), content);
        }

        private static string parseValue(object value)
        {
            if (value == null)
            {
                var log = "";
                foreach (var item in logPaths)
                {
                    log += item + " <-- ";
                }
                Debug.LogError("发现未知节点 " + log);
                return null;
            }

            string content = "";
            if (value is Enum)
            {
                content += (value.GetType().FullName.Replace('+', '.') + "." + value);
            }
            else if (value is string)
            {
                content += "\"" + value + "\"";
            }
            else if (value is bool)
            {
                content += value.ToString().ToLower();
            }
            else if (value is XNumber)
            {
                var num = (XNumber)value;
                content += string.Format("XNumber.create_row({0})", num.raw);
            }
            else if (value is XVector3)
            {
                var vec3 = (XVector3)value;
                content += string.Format("new XVector3(XNumber.create_row({0}), XNumber.create_row({1}), XNumber.create_row({2}))", vec3.x.raw, vec3.y.raw, vec3.z.raw);
            }
            else if (value is XVector2)
            {
                var vec2 = (XVector2)value;
                content += string.Format("new XVector2(XNumber.create_row({0}), XNumber.create_row({1}))", vec2.x.raw, vec2.y.raw);
            }
            else if (value is Array)
            {
                var array = value as Array;
                var child = "";
                foreach (var item in array)
                {
                    child += parseValue(item) + ", ";
                }

                var type = value.GetType().GetElementType();
                content += string.Format("new {0}[]{{ {1} }}", type.FullName.Replace('+', '.'), child);
            }
            else if (value is IList)
            {
                var list = value as IList;
                var child = "";
                foreach (var item in list)
                {
                    child += parseValue(item) + ", ";
                }

                var type = value.GetType().GetGenericArguments()[0];
                content += string.Format("new List<{0}>(){{ {1} }}", type.FullName.Replace('+', '.'), child);
            }
            else if (value.GetType().IsClass)
            {
                content += parseClass(value);
            }
            else
            {
                content += value.ToString();
            }

            return content;
        }

        private static string getLogPath()
        {
            var log = "";
            foreach (var item in logPaths)
            {
                log += item;
            }
            return log;
        }
    }
}